1 /*
2 * Copyright (C) 2014 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.base;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20
21 import com.google.common.annotations.GwtCompatible;
22
23 import javax.annotation.Nullable;
24
25 /**
26 * Helper functions that operate on any {@code Object}, and are not already provided in
27 * {@link java.util.Objects}.
28 *
29 * <p>See the Guava User Guide on <a
30 * href="http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained">writing
31 * {@code Object} methods with {@code MoreObjects}</a>.
32 *
33 * @author Laurence Gonsalves
34 * @since 18.0 (since 2.0 as {@code Objects})
35 */
36 @GwtCompatible
37 public final class MoreObjects {
38 /**
39 * Returns the first of two given parameters that is not {@code null}, if either is, or otherwise
40 * throws a {@link NullPointerException}.
41 *
42 * <p><b>Note:</b> if {@code first} is represented as an {@link Optional}, this can be
43 * accomplished with {@link Optional#or(Object) first.or(second)}. That approach also allows for
44 * lazy evaluation of the fallback instance, using {@link Optional#or(Supplier)
45 * first.or(supplier)}.
46 *
47 * @return {@code first} if it is non-null; otherwise {@code second} if it is non-null
48 * @throws NullPointerException if both {@code first} and {@code second} are null
49 * @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}.
50 */
51 public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
52 return first != null ? first : checkNotNull(second);
53 }
54
55 /**
56 * Creates an instance of {@link ToStringHelper}.
57 *
58 * <p>This is helpful for implementing {@link Object#toString()}.
59 * Specification by example: <pre> {@code
60 * // Returns "ClassName{}"
61 * MoreObjects.toStringHelper(this)
62 * .toString();
63 *
64 * // Returns "ClassName{x=1}"
65 * MoreObjects.toStringHelper(this)
66 * .add("x", 1)
67 * .toString();
68 *
69 * // Returns "MyObject{x=1}"
70 * MoreObjects.toStringHelper("MyObject")
71 * .add("x", 1)
72 * .toString();
73 *
74 * // Returns "ClassName{x=1, y=foo}"
75 * MoreObjects.toStringHelper(this)
76 * .add("x", 1)
77 * .add("y", "foo")
78 * .toString();
79 *
80 * // Returns "ClassName{x=1}"
81 * MoreObjects.toStringHelper(this)
82 * .omitNullValues()
83 * .add("x", 1)
84 * .add("y", null)
85 * .toString();
86 * }}</pre>
87 *
88 * <p>Note that in GWT, class names are often obfuscated.
89 *
90 * @param self the object to generate the string for (typically {@code this}), used only for its
91 * class name
92 * @since 18.0 (since 2.0 as {@code Objects.toStringHelper()}.
93 */
94 public static ToStringHelper toStringHelper(Object self) {
95 return new ToStringHelper(simpleName(self.getClass()));
96 }
97
98 /**
99 * Creates an instance of {@link ToStringHelper} in the same manner as {@link
100 * #toStringHelper(Object)}, but using the simple name of {@code clazz} instead of using an
101 * instance's {@link Object#getClass()}.
102 *
103 * <p>Note that in GWT, class names are often obfuscated.
104 *
105 * @param clazz the {@link Class} of the instance
106 * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}.
107 */
108 public static ToStringHelper toStringHelper(Class<?> clazz) {
109 return new ToStringHelper(simpleName(clazz));
110 }
111
112 /**
113 * Creates an instance of {@link ToStringHelper} in the same manner as {@link
114 * #toStringHelper(Object)}, but using {@code className} instead of using an instance's {@link
115 * Object#getClass()}.
116 *
117 * @param className the name of the instance type
118 * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}.
119 */
120 public static ToStringHelper toStringHelper(String className) {
121 return new ToStringHelper(className);
122 }
123
124 /**
125 * {@link Class#getSimpleName()} is not GWT compatible yet, so we
126 * provide our own implementation.
127 */
128 // Package-private so Objects can call it.
129 static String simpleName(Class<?> clazz) {
130 String name = clazz.getName();
131
132 // the nth anonymous class has a class name ending in "Outer$n"
133 // and local inner classes have names ending in "Outer.$1Inner"
134 name = name.replaceAll("\\$[0-9]+", "\\$");
135
136 // we want the name of the inner class all by its lonesome
137 int start = name.lastIndexOf('$');
138
139 // if this isn't an inner class, just find the start of the
140 // top level class name.
141 if (start == -1) {
142 start = name.lastIndexOf('.');
143 }
144 return name.substring(start + 1);
145 }
146
147 /**
148 * Support class for {@link MoreObjects#toStringHelper}.
149 *
150 * @author Jason Lee
151 * @since 18.0 (since 2.0 as {@code Objects.ToStringHelper}.
152 */
153 public static final class ToStringHelper {
154 private final String className;
155 private ValueHolder holderHead = new ValueHolder();
156 private ValueHolder holderTail = holderHead;
157 private boolean omitNullValues = false;
158
159 /**
160 * Use {@link MoreObjects#toStringHelper(Object)} to create an instance.
161 */
162 private ToStringHelper(String className) {
163 this.className = checkNotNull(className);
164 }
165
166 /**
167 * Configures the {@link ToStringHelper} so {@link #toString()} will ignore
168 * properties with null value. The order of calling this method, relative
169 * to the {@code add()}/{@code addValue()} methods, is not significant.
170 *
171 * @since 18.0 (since 12.0 as {@code Objects.ToStringHelper.omitNullValues()}.
172 */
173 public ToStringHelper omitNullValues() {
174 omitNullValues = true;
175 return this;
176 }
177
178 /**
179 * Adds a name/value pair to the formatted output in {@code name=value}
180 * format. If {@code value} is {@code null}, the string {@code "null"}
181 * is used, unless {@link #omitNullValues()} is called, in which case this
182 * name/value pair will not be added.
183 */
184 public ToStringHelper add(String name, @Nullable Object value) {
185 return addHolder(name, value);
186 }
187
188 /**
189 * Adds a name/value pair to the formatted output in {@code name=value}
190 * format.
191 *
192 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
193 */
194 public ToStringHelper add(String name, boolean value) {
195 return addHolder(name, String.valueOf(value));
196 }
197
198 /**
199 * Adds a name/value pair to the formatted output in {@code name=value}
200 * format.
201 *
202 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
203 */
204 public ToStringHelper add(String name, char value) {
205 return addHolder(name, String.valueOf(value));
206 }
207
208 /**
209 * Adds a name/value pair to the formatted output in {@code name=value}
210 * format.
211 *
212 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
213 */
214 public ToStringHelper add(String name, double value) {
215 return addHolder(name, String.valueOf(value));
216 }
217
218 /**
219 * Adds a name/value pair to the formatted output in {@code name=value}
220 * format.
221 *
222 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
223 */
224 public ToStringHelper add(String name, float value) {
225 return addHolder(name, String.valueOf(value));
226 }
227
228 /**
229 * Adds a name/value pair to the formatted output in {@code name=value}
230 * format.
231 *
232 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
233 */
234 public ToStringHelper add(String name, int value) {
235 return addHolder(name, String.valueOf(value));
236 }
237
238 /**
239 * Adds a name/value pair to the formatted output in {@code name=value}
240 * format.
241 *
242 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
243 */
244 public ToStringHelper add(String name, long value) {
245 return addHolder(name, String.valueOf(value));
246 }
247
248 /**
249 * Adds an unnamed value to the formatted output.
250 *
251 * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
252 * and give value a readable name.
253 *
254 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
255 */
256 public ToStringHelper addValue(@Nullable Object value) {
257 return addHolder(value);
258 }
259
260 /**
261 * Adds an unnamed value to the formatted output.
262 *
263 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
264 *
265 * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead
266 * and give value a readable name.
267 *
268 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
269 */
270 public ToStringHelper addValue(boolean value) {
271 return addHolder(String.valueOf(value));
272 }
273
274 /**
275 * Adds an unnamed value to the formatted output.
276 *
277 * <p>It is strongly encouraged to use {@link #add(String, char)} instead
278 * and give value a readable name.
279 *
280 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
281 */
282 public ToStringHelper addValue(char value) {
283 return addHolder(String.valueOf(value));
284 }
285
286 /**
287 * Adds an unnamed value to the formatted output.
288 *
289 * <p>It is strongly encouraged to use {@link #add(String, double)} instead
290 * and give value a readable name.
291 *
292 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
293 */
294 public ToStringHelper addValue(double value) {
295 return addHolder(String.valueOf(value));
296 }
297
298 /**
299 * Adds an unnamed value to the formatted output.
300 *
301 * <p>It is strongly encouraged to use {@link #add(String, float)} instead
302 * and give value a readable name.
303 *
304 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
305 */
306 public ToStringHelper addValue(float value) {
307 return addHolder(String.valueOf(value));
308 }
309
310 /**
311 * Adds an unnamed value to the formatted output.
312 *
313 * <p>It is strongly encouraged to use {@link #add(String, int)} instead
314 * and give value a readable name.
315 *
316 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
317 */
318 public ToStringHelper addValue(int value) {
319 return addHolder(String.valueOf(value));
320 }
321
322 /**
323 * Adds an unnamed value to the formatted output.
324 *
325 * <p>It is strongly encouraged to use {@link #add(String, long)} instead
326 * and give value a readable name.
327 *
328 * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
329 */
330 public ToStringHelper addValue(long value) {
331 return addHolder(String.valueOf(value));
332 }
333
334 /**
335 * Returns a string in the format specified by
336 * {@link MoreObjects#toStringHelper(Object)}.
337 *
338 * <p>After calling this method, you can keep adding more properties to later
339 * call toString() again and get a more complete representation of the
340 * same object; but properties cannot be removed, so this only allows
341 * limited reuse of the helper instance. The helper allows duplication of
342 * properties (multiple name/value pairs with the same name can be added).
343 */
344 @Override public String toString() {
345 // create a copy to keep it consistent in case value changes
346 boolean omitNullValuesSnapshot = omitNullValues;
347 String nextSeparator = "";
348 StringBuilder builder = new StringBuilder(32).append(className)
349 .append('{');
350 for (ValueHolder valueHolder = holderHead.next; valueHolder != null;
351 valueHolder = valueHolder.next) {
352 if (!omitNullValuesSnapshot || valueHolder.value != null) {
353 builder.append(nextSeparator);
354 nextSeparator = ", ";
355
356 if (valueHolder.name != null) {
357 builder.append(valueHolder.name).append('=');
358 }
359 builder.append(valueHolder.value);
360 }
361 }
362 return builder.append('}').toString();
363 }
364
365 private ValueHolder addHolder() {
366 ValueHolder valueHolder = new ValueHolder();
367 holderTail = holderTail.next = valueHolder;
368 return valueHolder;
369 }
370
371 private ToStringHelper addHolder(@Nullable Object value) {
372 ValueHolder valueHolder = addHolder();
373 valueHolder.value = value;
374 return this;
375 }
376
377 private ToStringHelper addHolder(String name, @Nullable Object value) {
378 ValueHolder valueHolder = addHolder();
379 valueHolder.value = value;
380 valueHolder.name = checkNotNull(name);
381 return this;
382 }
383
384 private static final class ValueHolder {
385 String name;
386 Object value;
387 ValueHolder next;
388 }
389 }
390
391 private MoreObjects() {}
392 }